package com.kelai.resource.impl;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.kelai.common.cache.RedisBean;
import com.kelai.common.constants.DeviceStatusEnum;
import com.kelai.domain.*;
import com.kelai.dto.DeviceManagerExcelDto;
import com.kelai.jms.listenner.adapter.RedisQueueMessageHandleAdapter;
import com.kelai.jms.message.queue.DeviceDataPacketQueueMessage;
import com.kelai.resource.IDeviceResource;
import com.kelai.resource.JsonCommonResource;
import com.kelai.response.JsonResponse;
import com.kelai.service.ICommonService;
import com.kelai.service.IDeviceDataService;
import com.kelai.service.IDeviceDayService;
import com.kelai.service.IStaticService;
import com.kelai.service.impl.DefaultCommonService;
import com.kelai.utils.ExcelUtils;
import com.kelai.utils.SystemTool;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备资源服务
 * Created by Silence on 2016/11/19.
 */
@SuppressWarnings("unchecked")
@RestController
@RequestMapping("/device")
public class DefaultDeviceResource extends JsonCommonResource implements IDeviceResource {

    private final static Logger logger = LoggerFactory.getLogger(DefaultDeviceResource.class);

    private ICommonService deviceService;

    private ICommonService deviceDayDataService;

    private ICommonService customerService;

    private ICommonService devicePackageDataService;

    private ICommonService errorMsgService;

    @Resource
    private IDeviceDataService deviceDataService;
    @Resource
    private IStaticService staticService;
    @Resource
    private IDeviceDayService deviceDayService;

    @Resource
    private RedisBean redisBean;

    @Autowired
    @Qualifier(value = "DeviceDataPacketQueueMessageHandleAdapter")
    private RedisQueueMessageHandleAdapter<DeviceDataPacketQueueMessage, Object> deviceDataPacketQueueMessageHandleAdapter;

    @RequestMapping(value = "/", method = RequestMethod.POST)
    @Override
    public JsonResponse<DeviceEntity> page(@RequestBody DeviceEntity deviceEntity) {

        if (deviceEntity.getProperties().get("_areaId") != null
                && !Objects.equals("", deviceEntity.getProperties().get("_areaId"))) {

            String shopIdCondition = deviceEntity.getProperties().get("_areaId").toString().replaceAll("-", ",");
            CustomerEntity customerCondition = new CustomerEntity();
            customerCondition.getProperties().put("status", 1);
            customerCondition.getProperties().put("id_in", shopIdCondition);
            if (deviceEntity.getProperties().get("_shopType") != null
                    && !Objects.equals("", deviceEntity.getProperties().get("_shopType"))) {
                customerCondition.getProperties().put("shopType", deviceEntity.getProperties().get("_shopType"));
            }
            if (deviceEntity.getProperties().get("customer_id_obj_in_ae") != null
                    && !Objects.equals("", deviceEntity.getProperties().get("customer_id_obj_in_ae"))) {
                customerCondition.getProperties().put("category", "3");
                customerCondition.getProperties().put("name_like", deviceEntity.getProperties().get("customer_id_obj_in_ae"));
            }
            if (deviceEntity.getProperties().get("_busiHourFilter") != null
                    && Objects.equals("1", deviceEntity.getProperties().get("_busiHourFilter"))) {
                customerCondition.getProperties().put("date_busihour", new Date());
            }
            List<AbstractEntity> customerList = customerService.listAll(customerCondition);
            List<String> customerIdList = Lists.newArrayList();
            customerList.forEach(item -> {
                customerIdList.add(item.getId());
            });
            String customerIds = Joiner.on(",").join(customerIdList);
            deviceEntity.getProperties().put("customer_id_obj_in_ae", customerIds);

        } else if (deviceEntity.getProperties().get("_shopType") != null
                && !Objects.equals("", deviceEntity.getProperties().get("_shopType"))) {

            CustomerEntity customerCondition = new CustomerEntity();
            customerCondition.getProperties().put("status", 1);
            customerCondition.getProperties().put("shopType", deviceEntity.getProperties().get("_shopType"));
            if (deviceEntity.getProperties().get("customer_id_obj_in_ae") != null
                    && !Objects.equals("", deviceEntity.getProperties().get("customer_id_obj_in_ae"))) {
                customerCondition.getProperties().put("category", "3");
                customerCondition.getProperties().put("name_like", deviceEntity.getProperties().get("customer_id_obj_in_ae"));
            }
            if (deviceEntity.getProperties().get("_busiHourFilter") != null
                    && Objects.equals("1", deviceEntity.getProperties().get("_busiHourFilter"))) {
                customerCondition.getProperties().put("date_busihour", new Date());
            }
            List<AbstractEntity> customerList = customerService.listAll(customerCondition);
            List<String> customerIdList = Lists.newArrayList();
            customerList.forEach(item -> {
                customerIdList.add(item.getId());
            });
            String customerIds = Joiner.on(",").join(customerIdList);
            deviceEntity.getProperties().put("customer_id_obj_in_ae", customerIds);

        } else if (deviceEntity.getProperties().get("customer_id_obj_in_ae") != null
                && !Objects.equals("", deviceEntity.getProperties().get("customer_id_obj_in_ae"))) {

            CustomerEntity customerCondition = new CustomerEntity();
            customerCondition.getProperties().put("status", 1);
            customerCondition.getProperties().put("category", "3");
            customerCondition.getProperties().put("name_like", deviceEntity.getProperties().get("customer_id_obj_in_ae"));
            if (deviceEntity.getProperties().get("_busiHourFilter") != null
                    && Objects.equals("1", deviceEntity.getProperties().get("_busiHourFilter"))) {
                customerCondition.getProperties().put("date_busihour", new Date());
            }
            List<AbstractEntity> customerList = customerService.listAll(customerCondition);
            List<String> customerIdList = Lists.newArrayList();
            customerList.forEach(item -> {
                customerIdList.add(item.getId());
            });
            String customerIds = Joiner.on(",").join(customerIdList);
            deviceEntity.getProperties().put("customer_id_obj_in_ae", customerIds);

        }
        Sort sort = new Sort(Sort.Direction.DESC, "customerId","lastReceiveTime");
        deviceEntity.getProperties().put("_sort", sort);
        //过滤掉老设备
//      deviceEntity.getProperties().put("type_not_equal","dtk1");
        JsonResponse rep = _pageAll(deviceService, deviceEntity);
        LocalDate now = LocalDate.now();
        String today = now.toString();
        String tomorrow = now.plusDays(1).toString();
        if (deviceEntity.getProperties().get("_day") != null) {

            List<String> deviceIdList = (List<String>) rep.getRows().stream().map(device -> {
                return ((DeviceEntity) device).getId();
            }).collect(Collectors.toList());

            Map<String, Object> map = Maps.newConcurrentMap();
            map.put("_startDate", today);
            map.put("_endDate", today);
            map.put("_deviceIds", deviceIdList);
            List<DeviceDataDayEntity> deviceDayList = deviceDayService.listAll(map);

            rep.getRows().forEach(a -> {
                if (a != null) {
                    DeviceEntity de = (DeviceEntity) a;
                    deviceDayList.forEach(deviceData -> {
                        if (Objects.equals(deviceData.getDevice().getId(), de.getId())) {
                            de.getProperties().put("dxIn", deviceData.getDxin());
                            de.getProperties().put("dxOut", deviceData.getDxout());
                        }
                    });
                }
            });
        }
        return rep;

    }

    @RequestMapping(value = "/getRepairDevice", method = RequestMethod.POST)
    public JsonResponse<DeviceEntity> getRepairDevice(@RequestBody DeviceEntity deviceEntity) {

        List<DeviceEntity> exceptionDevice = (List<DeviceEntity>) staticService.getAllDevice(deviceEntity.getProperties().get("userId").toString()).getProperties().get("exceptionDevices");

        return JsonResponse.build(exceptionDevice);

    }

    @RequestMapping(value = "/saveMemo", method = RequestMethod.POST)
    @Override
    public JsonResponse saveDeviceMemo(@RequestBody DeviceEntity deviceEntity) {

        DeviceEntity temp = (DeviceEntity) deviceService.findById(deviceEntity.getId());
        temp.setMemo(deviceEntity.getMemo());
        temp = (DeviceEntity) deviceService.saveInfo(temp);
        JsonResponse jsonResponse = JsonResponse.OK();
        Map<String, Object> extProps = new HashMap<String, Object>();
        if (temp != null && deviceEntity.getMemo().equals(temp.getMemo())) {
            extProps.put("flag", true);
        } else {
            extProps.put("flag", false);
        }
        jsonResponse.setExtProps(extProps);
        return jsonResponse;
    }

    /**
     * 导出
     *
     * @param
     * @return
     */
    @RequestMapping(value = "/export_download", method = RequestMethod.POST, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public ResponseEntity<InputStreamResource> export(String _areaId, String _shopType, String customer_id_obj_in_ae,
                                                      String _busiHourFilter, String code_like, String status_in_num,
                                                      String _day, String customerId, String isQuery) throws IOException {

        DeviceDataEntity deviceEntity = new DeviceDataEntity();
        deviceEntity.getProperties().put("_areaId", _areaId);
        deviceEntity.getProperties().put("_shopType", _shopType);
        deviceEntity.getProperties().put("customer_id_obj_in_ae", customer_id_obj_in_ae);
        deviceEntity.getProperties().put("_busiHourFilter", _busiHourFilter);
        deviceEntity.getProperties().put("code_like", code_like);
        deviceEntity.getProperties().put("status_in_num", status_in_num);
        deviceEntity.getProperties().put("_day", _day);
        deviceEntity.getProperties().put("customerId", customerId);

        if (deviceEntity.getProperties().get("_areaId") != null
                && !Objects.equals("", deviceEntity.getProperties().get("_areaId"))) {

            String shopIdCondition = deviceEntity.getProperties().get("_areaId").toString().replaceAll("-", ",");
            CustomerEntity customerCondition = new CustomerEntity();
            customerCondition.getProperties().put("id_in", shopIdCondition);
            if (deviceEntity.getProperties().get("_shopType") != null
                    && !Objects.equals("", deviceEntity.getProperties().get("_shopType"))) {
                customerCondition.getProperties().put("shopType", deviceEntity.getProperties().get("_shopType"));
            }
            if (deviceEntity.getProperties().get("customer_id_obj_in_ae") != null
                    && !Objects.equals("", deviceEntity.getProperties().get("customer_id_obj_in_ae"))) {
                customerCondition.getProperties().put("category", "3");
                customerCondition.getProperties().put("name_like", deviceEntity.getProperties().get("customer_id_obj_in_ae"));
            }
            if (deviceEntity.getProperties().get("_busiHourFilter") != null
                    && Objects.equals("1", deviceEntity.getProperties().get("_busiHourFilter"))) {
                customerCondition.getProperties().put("date_busihour", new Date());
            }
            List<AbstractEntity> customerList = customerService.listAll(customerCondition);
            List<String> customerIdList = Lists.newArrayList();
            customerList.forEach(item -> {
                customerIdList.add(item.getId());
            });
            String customerIds = Joiner.on(",").join(customerIdList);
            deviceEntity.getProperties().put("customer_id_obj_in_ae", customerIds);

        } else if (deviceEntity.getProperties().get("_shopType") != null
                && !Objects.equals("", deviceEntity.getProperties().get("_shopType"))) {

            CustomerEntity customerCondition = new CustomerEntity();
            customerCondition.getProperties().put("shopType", deviceEntity.getProperties().get("_shopType"));
            if (deviceEntity.getProperties().get("customer_id_obj_in_ae") != null
                    && !Objects.equals("", deviceEntity.getProperties().get("customer_id_obj_in_ae"))) {
                customerCondition.getProperties().put("category", "3");
                customerCondition.getProperties().put("name_like", deviceEntity.getProperties().get("customer_id_obj_in_ae"));
            }
            if (deviceEntity.getProperties().get("_busiHourFilter") != null
                    && Objects.equals("1", deviceEntity.getProperties().get("_busiHourFilter"))) {
                customerCondition.getProperties().put("date_busihour", new Date());
            }
            List<AbstractEntity> customerList = customerService.listAll(customerCondition);
            List<String> customerIdList = Lists.newArrayList();
            customerList.forEach(item -> {
                customerIdList.add(item.getId());
            });
            String customerIds = Joiner.on(",").join(customerIdList);
            deviceEntity.getProperties().put("customer_id_obj_in_ae", customerIds);

        } else if (deviceEntity.getProperties().get("customer_id_obj_in_ae") != null
                && !Objects.equals("", deviceEntity.getProperties().get("customer_id_obj_in_ae"))) {

            CustomerEntity customerEntity = new CustomerEntity();
            customerEntity.getProperties().put("category", "3");
            customerEntity.getProperties().put("name_like", deviceEntity.getProperties().get("customer_id_obj_in_ae"));
            if (deviceEntity.getProperties().get("_busiHourFilter") != null
                    && Objects.equals("1", deviceEntity.getProperties().get("_busiHourFilter"))) {
                customerEntity.getProperties().put("date_busihour", new Date());
            }
            List<AbstractEntity> customerList = customerService.listAll(customerEntity);
            List<String> customerIdList = Lists.newArrayList();
            customerList.forEach(item -> {
                customerIdList.add(item.getId());
            });
            String customerIds = Joiner.on(",").join(customerIdList);
            deviceEntity.getProperties().put("customer_id_obj_in_ae", customerIds);

        }

        List<DeviceManagerExcelDto> datas = Lists.newArrayList();

        JsonResponse rep = _pageAll(deviceService, deviceEntity);
        LocalDate now = LocalDate.now();
        String today = now.toString();
        String tomorrow = now.plusDays(1).toString();
        List<String> _deviceIds = Lists.newArrayList();

        if (deviceEntity.getProperties().get("_day") != null) {
            rep.getRows().forEach(a -> {
                if (a != null) {
                    DeviceEntity de = (DeviceEntity) a;

                    DeviceManagerExcelDto excelDto = new DeviceManagerExcelDto();
                    excelDto.setId(de.getId());
                    excelDto.setProvince(de.getProvince());
                    excelDto.setCity(de.getCity());
                    excelDto.setCode(de.getCode());
                    excelDto.setCustomerName(de.getCustomerName());
                    excelDto.setStatusName(de.getStatusName());

                    if (!Objects.equals(de.getStatus(), "1")) {
                        excelDto.setFocus((de.getFocus() != null && Objects.equals(de.getFocus(), 1)) ? "失焦" : "正常");
                    } else {
                        excelDto.setFocus("-");
                    }

                    if (!Objects.equals(de.getStatus(), "1")) {
                        excelDto.setVoltage((de.getVoltage() != null ? de.getVoltage().toString() : "0") + "%");
                    } else {
                        excelDto.setVoltage("-");
                    }

                    if (de.getLastReceiveTime() != null) {
                        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                        LocalDateTime newDate = new Date(de.getLastReceiveTime()).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                        String newDateStr = newDate.format(dateTimeFormatter);
                        excelDto.setLastReceiveTime(newDateStr);
                    } else {
                        excelDto.setLastReceiveTime("-");
                    }

                    datas.add(excelDto);
                    _deviceIds.add(de.getId());
                }
            });
        }

        Map<String, Object> condition = Maps.newConcurrentMap();
        condition.put("_startDate", today);
        condition.put("_endDate", tomorrow);
        condition.put("_deviceIds", _deviceIds);
        EmptyEntity obj = staticService.sumForDeviceDay(condition);
        List<DeviceManagerExcelDto> newdatas = Lists.newArrayList();
        newdatas = datas.stream().map(data -> {
            DeviceManagerExcelDto newData = data;

            String customerNums = obj.getProperties().get(data.getId()) != null
                    ? obj.getProperties().get(data.getId()).toString() : "0-0";
            String[] customerNumsArray = customerNums.split("-");
            newData.setDxin(customerNumsArray[0]);
            newData.setDxout(customerNumsArray[1]);

            return newData;
        }).collect(Collectors.toList());

        File templateFile = null;
        if ("true".equals(isQuery)) {//是否为设备查询
            templateFile = ExcelUtils.export(DeviceManagerExcelDto.class, "设备查询统计", "设备查询统计", newdatas);
        } else {
            templateFile = ExcelUtils.export(DeviceManagerExcelDto.class, "设备管理统计", "设备管理统计", newdatas);
        }


        FileSystemResource file = new FileSystemResource(templateFile);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Content-Disposition", "attachment; filename=" + new String((file.getFilename()).getBytes("gb2312"), "iso-8859-1"));
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");
        return ResponseEntity
                .ok()
                .headers(headers)
                .contentLength(file.contentLength())
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .body(new InputStreamResource(file.getInputStream()));
    }

    @RequestMapping(value = "/cascading", method = RequestMethod.POST)
    public JsonResponse<DeviceEntity> cascading(@RequestBody DeviceEntity deviceEntity) {

        String customerName = (String) deviceEntity.getProperties().get("customer_id_obj_in_ae");
        if (StringUtils.isNotEmpty(customerName)) {
            CustomerEntity customerEntity = new CustomerEntity();
            customerEntity.getProperties().put("category", "3");
            customerEntity.getProperties().put("name_like", customerName);
            List<AbstractEntity> customerList = customerService.listAll(customerEntity);
            List<String> customerIdList = Lists.newArrayList();
            customerList.forEach(item -> {
                customerIdList.add(item.getId());
            });
            String customerIds = Joiner.on(",").join(customerIdList);
            deviceEntity.getProperties().put("customer_id_obj_in_ae", customerIds);
        }

        JsonResponse rep = _pageAll(deviceService, deviceEntity);
        LocalDate now = LocalDate.now();
        String today = now.toString();
        String tomorrow = now.plusDays(1).toString();
        if (deviceEntity.getProperties().get("_day") != null) {
            String d = LocalDate.now().toString().replace("-", "");
            rep.getRows().forEach(a -> {
                if (a != null) {
//                    DeviceEntity de = (DeviceEntity) a;
//                    DeviceDayDataEntity da = (DeviceDayDataEntity) deviceDayDataService.findByCode(de.getCode() + "-" + d);
//                    if (da != null) {
//                        de.getProperties().put("dxIn", da.getDxin());
//                        de.getProperties().put("dxOut", da.getDxout());
//                    }
                    DeviceEntity de = (DeviceEntity) a;
                    Map<String, Object> condition = Maps.newConcurrentMap();
                    condition.put("_startDate", today);
                    condition.put("_endDate", tomorrow);
                    condition.put("device_id_obj_ae", de.getId());
                    EmptyEntity obj = staticService.sumForDeviceDay(condition);
                    de.getProperties().put("dxIn", obj.getProperties().get("totalin"));
                    de.getProperties().put("dxOut", obj.getProperties().get("totalout"));
                }
            });
        }
        return rep;
    }

    @RequestMapping(value = "/cascading2", method = RequestMethod.POST)
    public JsonResponse<DeviceEntity> cascading2(@RequestBody DeviceEntity deviceEntity) {

        DeviceEntity cond = new DeviceEntity();
        cond.getProperties().put("customer_id_obj_ae", deviceEntity.getProperties().get("customer_id_obj_ae"));

        JsonResponse rep = _pageAll(deviceService, cond);
        LocalDate now = LocalDate.now();
        String today = now.toString();
        String tomorrow = now.plusDays(1).toString();
        if (deviceEntity.getProperties().get("_day") != null) {
            String d = LocalDate.now().toString().replace("-", "");
            rep.getRows().forEach(a -> {
                if (a != null) {
//                    DeviceEntity de = (DeviceEntity) a;
//                    DeviceDayDataEntity da = (DeviceDayDataEntity) deviceDayDataService.findByCode(de.getCode() + "-" + d);
//                    if (da != null) {
//                        de.getProperties().put("dxIn", da.getDxin());
//                        de.getProperties().put("dxOut", da.getDxout());
//                    }
                    DeviceEntity de = (DeviceEntity) a;
                    Map<String, Object> condition = Maps.newConcurrentMap();
                    condition.put("_startDate", today);
                    condition.put("_endDate", tomorrow);
                    condition.put("device_id_obj_ae", de.getId());
                    EmptyEntity obj = staticService.sumForDeviceDay(condition);
                    de.getProperties().put("dxIn", obj.getProperties().get("totalin"));
                    de.getProperties().put("dxOut", obj.getProperties().get("totalout"));
                }
            });
        }
        return rep;
    }

    @RequestMapping(value = "/findDeviceByParentId/{parentId}", method = RequestMethod.GET)
    @Override
    public JsonResponse<DeviceEntity> findDeviceByParentId(@PathVariable String parentId) {

        DeviceEntity org = new DeviceEntity();
        org.getProperties().put("customer_id_obj_in_ae", parentId);
        return _pageAll(deviceService, org);

    }

    /*
    @RequestMapping(value = "/cacheStop", method = RequestMethod.GET)
    @Override
    public String stopCacheData() {
        cacheBean.stop();
        return "1";
    }
    @RequestMapping(value = "/cacheSize", method = RequestMethod.GET)
    @Override
    public String cacheSize() {
        return cacheBean.getQueueSize()+"";
    }
    */

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @Override
    public JsonResponse<DeviceEntity> findById(@PathVariable String id) {
        return _findOne(deviceService, id, 0);
    }

    @RequestMapping(value = "/code/{code}", method = RequestMethod.GET)
    @Override
    public JsonResponse<DeviceEntity> findByCode(@PathVariable String code) {
        return _findOne(deviceService, code, 1);
    }

    @RequestMapping(value = "/cascading", method = RequestMethod.PUT)
    @Override
    public JsonResponse<DeviceEntity> save(@RequestBody DeviceEntity deviceEntity) {
        CustomerEntity ce = (CustomerEntity) customerService.findById(deviceEntity.getCustomer().getId());
        deviceEntity.setCustomerId(ce.getTopCustomerId());
        return _saveInfo(deviceService, deviceEntity);
    }

    @RequestMapping(value = "/updateCustomerId", method = RequestMethod.PUT)
    @Override
    public JsonResponse<DeviceEntity> updateCustomerId(@RequestBody DeviceEntity deviceEntity) {

        List<DeviceEntity> deviceList = (List<DeviceEntity>) _pageAll(deviceService, deviceEntity).getRows();
        if (CollectionUtils.isNotEmpty(deviceList)) {
            for (DeviceEntity device : deviceList) {
                if (!Objects.equals(deviceEntity.getProperties().get("_customerId"), device.getCustomerId())) {
                    device.setCustomerId(deviceEntity.getProperties().get("_customerId").toString());
                    _saveInfo(deviceService, device);
                }
            }
        }
        return JsonResponse.OK();

    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    @Override
    public JsonResponse<DeviceEntity> delete(@PathVariable String id) {
        return _delete(deviceService, id);
    }


    @RequestMapping(value = "/error/", method = RequestMethod.POST)
    @Override
    public JsonResponse<ErrorMsgEntity> pageErrorMsg(@RequestBody ErrorMsgEntity errorMsgEntity) {

        return _pageAll(errorMsgService, errorMsgEntity);

    }

    @Override
    public void initService() {
        if (deviceService == null)
            deviceService = new DefaultCommonService("deviceRepository");
        if (deviceDayDataService == null)
            deviceDayDataService = new DefaultCommonService("deviceDayDataRepository");
        if (customerService == null)
            customerService = new DefaultCommonService("customerRepository");
        if (devicePackageDataService == null)
            devicePackageDataService = new DefaultCommonService("devicePackageDataRepository");
        if (errorMsgService == null)
            errorMsgService = new DefaultCommonService("errorMsgRepository");
    }

    /**
     * 设备通讯
     *
     * @param map
     * @return
     */
    @RequestMapping(value = "/receive/", method = RequestMethod.POST)
    @Override
    public String receiveData(@RequestBody Map<String, Object> map) {
//        logger.info(map.toString());
        String ret = "";
        if (map.get("cmd") == null)
            return "result=00";
        String cmd = map.get("cmd").toString();
        if (cmd.equals("getsetting")) {
            ret = getsetting(map.get("data").toString(), map.get("flag").toString());
        } else if (cmd.equals("cache")) {
            ret = cacheData(map.get("data").toString(), map.get("status").toString(), map.get("flag").toString(), map.get("count"), map.get("Tend"));
        } else if (cmd.equals("video")) {
            ret = videoData(map.get("data").toString());
        }
//        logger.info(ret);
        return "result=" + ret;
    }

    /**
     * 设备被重新进行网络设定时或重新开机发送请求
     *
     * @param data
     * @param flag
     * @return
     */
    private String getsetting(String data, String flag) {
        System.out.println("~~~ enter getsetting~~~ (" + LocalDateTime.now() + ")");
        //如果crc校验不通过，则返回空字符串
        if (!checkCrc(data)) {
            return "";
        }
        String sn = getSn(data.substring(0, 8)).toUpperCase();
        DeviceEntity device = (DeviceEntity) deviceService.findByCode(sn);
        Integer sh = 9, sm = 0, eh = 22, em = 30;
        if (device != null) {
            device.setLastReceiveTime(System.currentTimeMillis());
            device.setCommandType(Byte.decode("0x" + data.substring(8, 10)).intValue());
            device.setSpeed(Byte.decode("0x" + data.substring(10, 12)).intValue());
            device.setRecordCycle(Byte.decode("0x" + data.substring(12, 14)).intValue());
            if (!data.substring(14, 16).equals("A0")){
                device.setUploadCycle(Byte.decode("0x" + data.substring(14, 16)).intValue());
            }
            device.setFixTimeUpload(Byte.decode("0x" + data.substring(16, 18)).intValue());
            device.setStatus(DeviceStatusEnum.ENABLE.getValue());
            deviceService.saveInfo(device);
            CustomerEntity ce = device.getCustomer();
            String[] s;
            if (ce.getOpenTime() != null) {
                s = ce.getOpenTime().split(":");
                sh = Integer.decode(s[0]);
                sm = Integer.decode(s[1]);
            }
            if (ce.getCloseTime() != null) {
                s = ce.getCloseTime().split(":");
                eh = Integer.decode(s[0]);
                em = Integer.decode(s[1]);
            }
            System.out.println("~~~ sh ~~~ (" + sh + ")");
            System.out.println("~~~ eh ~~~ (" + eh + ")");
        } else {
            logger.info("setting: Device miss config..." + sn);
        }
        if (device == null) {
            device = new DeviceEntity();
        }
        int tm = 8;
        if (device.getCustomer() != null &&
                device.getCustomer().getTimeZone() != null) {
            tm = Integer.parseInt(device.getCustomer().getTimeZone());
        }
        LocalDateTime now = LocalDateTime.now();

        Integer[] param = new Integer[34];
        param[0] = 4;
        param[1] = -3;
        param[2] = -1;
        param[3] = 3;
        param[4] = 0;
        param[5] = device.getRecordPeriod() == null ? 0 : device.getRecordPeriod();
        param[6] = device.getUploadPeriod() == null ? 5 : device.getUploadPeriod();
        param[7] = 0;
        param[8] = 0;
        param[9] = 0;
        param[10] = 0;
        param[11] = 0;
        param[12] = 0;
        param[13] = 0;
        param[14] = 0;
        param[15] = 0;
        param[16] = 0;
        param[17] = 2;
        param[18] = 0;
        param[19] = 0;
        param[20] = 0;
        param[21] = now.getYear() - 2000;
        param[22] = now.getMonthValue();
        param[23] = now.getDayOfMonth();
        param[24] = now.getHour() - 8 + tm;
        param[25] = now.getMinute();
        param[26] = now.getSecond();
//        param[27] = now.getDayOfWeek().getValue();
        param[27] = 0;
        param[28] = sh;
        param[29] = sm;
        param[30] = eh;
        param[31] = em;
        param[32] = 0;
        param[33] = 0;
        //开始做校时, 只做到分钟
        if (Objects.equals(Integer.decode("0x" + data.substring(80, 82)), param[21])
                && Objects.equals(Integer.decode("0x" + data.substring(82, 84)), param[22])
                && Objects.equals(Integer.decode("0x" + data.substring(84, 86)), param[23])
                && Objects.equals(Integer.decode("0x" + data.substring(86, 88)), param[24])
                && Objects.equals(Integer.decode("0x" + data.substring(88, 90)), param[25])
                ) {
            param[0] = 5;
        }
        StringBuilder sb = new StringBuilder();
        int i = 0;
        for (Integer aParam : param) {
            if (i == 1)
                sb.append(flag);
            else if (i == 2)
                sb.append(data.substring(0, 8));
            else if (i == 18 || i == 19 || i == 20)
                sb.append("00000000000000");
            else
                sb.append(hexFormat(aParam));
            i++;
        }
        System.out.println("before crc:" + sb.toString());
        String crcStr = SystemTool.crcCheck(sb.toString());
        System.out.println("after crc:" + crcStr);
        sb.append(crcStr);
        System.out.println("~~~~ return ~~~~ : " + sb.toString().toUpperCase());
        return sb.toString().toUpperCase();
    }

    /**
     * 上传设备缓存数据
     *
     * @param data
     * @param status
     * @param flag
     * @param count
     * @param tend
     * @return
     */
    private String cacheData(String data, String status, String flag, Object count, Object tend) {
        //    {cmd=cache, flag=3B00, status=0101B1098EF701E20E4600 01 A675, data=[100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD, 100B1E131600000000000000000000D5FD], count=000A, temp=8C0, Tend=nnnnnnnnnnnnnnnnnnT}
        //logger.info("~~~~~~接收设备数据包开始 flag:" + flag);
        long startTime = System.currentTimeMillis();    //获取开始时间

        if (status != null && status.length() > 22) {
            String sn = getSn(status.substring(4, 12)).toUpperCase();
            long a = System.currentTimeMillis();    //获取开始时间
            DeviceEntity device = (DeviceEntity) deviceService.findByCode(sn);
            Integer sh = 9, sm = 0, eh = 22, em = 30;
            Boolean storeFlag = null; //是否保存入库的标识
            if (device != null) {
                device.setLastReceiveTime(System.currentTimeMillis());

                //逻辑:连续两个小时失焦才算是真的失焦
                //若此时设备失焦，在缓存中查找是否有该设备存在，若没有，则插入当前失焦时间
                //若已经存在，则将当前时间与之前存在的时间做比较，若超过一个小时，则算失焦
                //若设备没有失焦，则删除缓存中的对应设备的失焦数据
                Integer focus = Integer.decode("0x" + status.substring(12, 14));
                String focusDateStr = redisBean.get("device_" + device.getId());
                if (Objects.equals(1, focus)) {
                    if (StringUtils.isNotEmpty(focusDateStr)) {
                        LocalDateTime focusDate = LocalDateTime.parse(focusDateStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                        LocalDateTime now = LocalDateTime.now();
                        if (focusDate.plusHours(2).compareTo(now) < 0) {
                            focus = 1;
                        } else {
                            focus = 0;
                        }
                    } else {
                        Map<String, String> map = Maps.newConcurrentMap();
                        map.put("key", "device_" + device.getId());
                        map.put("value", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
                        redisBean.add(map);
                        focus = 0;
                    }
                } else {
                    if (StringUtils.isNotEmpty(focusDateStr)) {
                        redisBean.delete("device_" + device.getId());
                    }
                    focus = 0;
                }
                device.setFocus(focus);

                //TODO start 这里电压和电量字段存反了，暂时将错就错
                //TODO 原电压字段现用于发射器电量(新设备)
//                device.setBattery(Integer.decode("0x" + status.substring(14, 18)));
                Integer iBattery = Integer.decode("0x" + status.substring(14, 16));
                String battery = iBattery.toString();
                String battery_text = status.substring(16, 18);
                device.setBattery(battery + battery_text);
                device.setVoltage(Integer.decode("0x" + status.substring(18, 20)));
                //TODO end 这里电压和电量字段存反了，暂时将错就错
                device.setCharge(Integer.decode("0x" + status.substring(20, 22)));
                Integer afterCheckStatus = checkDeviceStatus(focus,
                        Integer.decode("0x" + status.substring(18, 20)));
                device.setStatus(afterCheckStatus);
                deviceService.saveInfo(device);
                long b = System.currentTimeMillis();    //获取开始时间
                //logger.info("查找和更新设备"+sn+"耗时： " + (b - a) + "ms");
                CustomerEntity ce = device.getCustomer();
                String[] s;
                if (ce.getOpenTime() != null) {
                    s = ce.getOpenTime().split(":");
                    sh = Integer.decode(s[0]);
                    sm = Integer.decode(s[1]);
                }
                if (ce.getCloseTime() != null) {
                    s = ce.getCloseTime().split(":");
                    eh = Integer.decode(s[0]);
                    em = Integer.decode(s[1]);
                }
                storeFlag = true;
            } else {
                logger.info("cacheData: Device miss config..." + sn);
                storeFlag = false;
            }
            int retFlg = 0;
            boolean crc = true;
            if (data != null) {
                data = data.replaceAll("\\[", "").replaceAll("]", "").replaceAll(" ", "");
                //将数据包加入队列
                DevicePackageDataEntity dpde = new DevicePackageDataEntity();
                dpde.setCmd("cache");
                dpde.setCount(String.valueOf(count));
                dpde.setFlag(flag);
                dpde.setData(data);
                dpde.setState(status);
                dpde.setTend(String.valueOf(tend));
                dpde.setReceiveDateTime(new Date());
                dpde.getProperties().put("device", device);


                String[] ss = data.split(",");
                String[] mss = new String[ss.length];
                Integer _count = 0;
                if (count != null) {
                    _count = Integer.decode("0x" + count.toString());
                }
                //先做一次crc校验
                int i = 0;
                for (String s : ss) {
                    s = s.trim();
                    if (s.length() < 30) {
                        continue;
                    }
                    mss[i] = s;
                    if (!checkCrc(s)) { //只要有一个不对，则全部丢弃
                        crc = false;
                        break;
                    }
                    i++;
                }
                if (crc && _count == ss.length) {
                    dpde.getProperties().put("flag", true);
                    retFlg = 1;
                }
                if (storeFlag) {
                    if("09FEF63D".equals(device.getCode())){
                        System.out.println("AAAAAAAAAA " + LocalDateTime.now() + " : " + dpde);
                    }
                    DeviceDataPacketQueueMessage msg = new DeviceDataPacketQueueMessage(dpde);
                    deviceDataPacketQueueMessageHandleAdapter.sendMessage(msg);
                }
            }
            LocalDateTime now = LocalDateTime.now();
            Integer[] param = new Integer[14];
            if (retFlg == 1 && tend == null) {
                retFlg = 0;
            }
            int tm = 8;
            if (device != null &&
                    device.getCustomer() != null &&
                    device.getCustomer().getTimeZone() != null) {
                if (!device.getCustomer().getTimeZone().equals("点军区")) {
                    tm = Integer.parseInt(device.getCustomer().getTimeZone());
                }
            }
            param[0] = retFlg;
            param[1] = -3;
            param[2] = 1;
            param[3] = now.getYear() - 2000;
            param[4] = now.getMonthValue();
            param[5] = now.getDayOfMonth();
            param[6] = now.getHour() - 8 + tm;
            param[7] = now.getMinute();
            param[8] = now.getSecond();
//            param[9] = now.getDayOfWeek().getValue();
            param[9] = 0;
//            param[10] = 9;
//            param[11] = 0;
//            param[12] = 22;
//            param[13] = 30;
            param[10] = sh;
            param[11] = sm;
            param[12] = eh;
            param[13] = em;
            StringBuilder sb = new StringBuilder();
            int i = 0;
            for (Integer aParam : param) {
                if (i == 1)
                    sb.append(flag.substring(2, 4)).append(flag.substring(0, 2));
                else
                    sb.append(hexFormat(aParam));
                i++;
            }
            sb.append(SystemTool.crcCheck(sb.toString()));
            long endTime = System.currentTimeMillis();    //获取结束时间
            //logger.info("返回给设备数据"+sb.toString().toUpperCase()+"，从接收数据到放入队列池耗时： " + (endTime - startTime) + "ms，接收设备数据包结束~~~~~~");
            return sb.toString().toUpperCase();
        }
        long endTime = System.currentTimeMillis();    //获取结束时间
        //logger.info("返回给设备数据000000000000000000000000000000BF40，从接收数据到放入队列池耗时： " + (endTime - startTime) + "ms，接收设备数据包结束~~~~~~~");
        return "000000000000000000000000000000BF40";
    }

    private String videoData(String data) {
        //24 30 20161207 0000 00004931 00000123 00000000 00000010 49310600103900000015 23
        if (data.length() > 68) {
            String sn = data.substring(24, 32);
            String body = data.substring(48, 68);
            DeviceEntity device = (DeviceEntity) deviceService.findByCode(sn);
            if (device != null) {
                device.setStatus(2);
                device.setLastReceiveTime(System.currentTimeMillis());
                deviceService.saveInfo(device);
            }
            //4931 06 001039 0000 0015
            if (body.startsWith("4931")) {
                Integer dxIn = Integer.parseInt(body.substring(12, 16));
                Integer dxOut = Integer.parseInt(body.substring(16, 20));
                if (dxIn + dxOut > 0) {
                    String t = data.substring(4, 12) + body.substring(8, 12) + body.substring(6, 8);
                    DeviceDataEntity de = deviceDataService.findByCode(sn + t);
                    if (de == null) {
                        de = _dataDevice(sn, t, device);
                        de.getProperties().put("_repeat", "0");
                    } else {
                        de.getProperties().put("_repeat", "1");
                    }
                    de.setFocus(1);
                    de.setDxin(dxIn);
                    de.setDxout(dxOut);
                    _saveInfo(deviceDataService, de);
                }
            }
        }
        return "";
    }

    private DeviceDataEntity _dataDevice(String sn, String t, DeviceEntity device) {
        DeviceDataEntity de = new DeviceDataEntity();
        de.setCode(sn + t);
        de.setName(sn);
        de.setSn(sn);
        de.setHappenTime(Long.parseLong(t));
        if (device != null) {
            de.setDevice(device);
            if (device.getCustomer() != null) {
                de.setCustomer(device.getCustomer());
                de.setCustomerId(device.getCustomer().getTopCustomerId());
            }
        }
        return de;
    }

    private boolean checkCrc(String s) {
        if (s.length() < 4)
            return false;
        int n = s.length() - 4;
        return SystemTool.crcCheck(s.substring(0, n)).toUpperCase().equals(s.substring(n).toUpperCase());
    }

    private String getSn(String hexString) {
        String hv = null;
        StringBuilder sb = new StringBuilder();
        byte[] bb = SystemTool.convert16HexToByte(hexString);
        for (byte b : bb) {
            int v = b & 0xFF;
            hv = Integer.toHexString(v);
            hv = (hv.length() == 1 ? "0" + hv : hv);
            sb.insert(0, hv);
        }
        return sb.toString();
    }

    private String hexFormat(Integer v) {
        String s = Integer.toHexString(v);
        return s.length() == 1 ? "0" + s : s;
    }

    private String deHexFormat(String s) {
        Integer i = Integer.decode("0x" + s);
        return i < 10 ? "0" + i : i.toString();
    }

    /**
     * 检查设备状态
     *
     * @param focus   是否失焦
     * @param battery 电量
     * @return
     */
    private Integer checkDeviceStatus(Integer focus, Integer battery) {

        Integer result = DeviceStatusEnum.ENABLE.getValue();

        if (Objects.equals(focus, 1)) {//如果失焦，则状态异常
            result = DeviceStatusEnum.DISABLE.getValue();
        } else if (battery != null && battery.intValue() < 10) {//如果电量小于10%，则状态异常
            result = DeviceStatusEnum.DISABLE.getValue();
        }

        return result;
    }
}
